
#include <stdlib.h>

#include "functions.h"

/*
 * variables facility
 */

static int
idobj_pair_cmp( const void * lhs, const void * rhs )
{
    const IdObjPair *   l = lhs;
    const IdObjPair *   r = rhs;

    return idcmp( l->var, r->var );
}

static IdObjPair *
find_idobj_pair( RuleEngineContext * r, Id * var )
{
    IdObjPair   p;
    p.var = var;
    return bsearch( &p, r->vars.pairs, r->vars.size, sizeof(IdObjPair), idobj_pair_cmp );
}

static Obj *
conv_id( RuleEngineContext * r, Id * id )
{
    Obj * result = getvar( r, id );
    return (0 != result ? result : (Obj *)id);
}


void initialize_vars( RuleEngineContext * r )
{
    assert( r->vars.size == 0 );
    set_id_evaluator_handler( r->eval, conv_id, r );
}

void free_vars( RuleEngineContext * r )
{
    ql_free( r->vars.pairs );
}

Obj *
getvar( RuleEngineContext * r, Id * var )
{
    IdObjPair * var_pair = find_idobj_pair( r, var );
    if( var_pair != 0 )
    {
        return var_pair->value;
    }

    return 0;
}

void
setvar( RuleEngineContext * r, Id * var, Obj * value )
{
    IdObjPair *         p = find_idobj_pair( r, var );

    if( 0 == p )
    {
        if( r->vars.allocated < r->vars.size + 1 )
        {
            r->vars.allocated = r->vars.allocated + QL_IDOBJ_PAIRS_ARR_GROW_SIZE;

            r->vars.pairs = ql_realloc( r->alloc_ctx, r->vars.pairs,
                sizeof(IdObjPair) * (r->vars.allocated - 1) );
        }

        p = &r->vars.pairs[r->vars.size ++];
        p->var = var;

        qsort( r->vars.pairs, r->vars.size, sizeof(IdObjPair), idobj_pair_cmp );

        p = find_idobj_pair( r, var );
        assert( p != 0 );
    }

    p->value = value;
}

/*
 * functions
 */


Obj *
f_setvar( void * tag, List * args )
{
    RuleEngineContext * r = tag;

    // arguments check: there shall be 2 arguments, and first one shall be id
    if( list_length(args) != 2 || args->car->type != OBJ_ID )
    {
        evaluator_emit_error( r->eval, QL_ERR_INVALID_ARGUMENTS );
    }

    setvar( r, (Id *)args->car, args->cdr->car );

    return args->cdr->car;
}

